package com.gitee.ywj1352.client;


import com.alibaba.fastjson.JSON;
import com.gitee.ywj1352.api.RpcfxRequest;
import com.gitee.ywj1352.api.RpcfxResponse;
import com.gitee.ywj1352.config.RpcxProxyConfig;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.matcher.ElementMatchers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;

import java.io.IOException;
import java.lang.reflect.Method;

public class RpcClientInvoker {


    public static <T> Object createProxy(Class<T> interfaceType, RpcxProxyConfig proxyConfig) throws Exception{
        ByteBuddyProxyHandler handler = new ByteBuddyProxyHandler(proxyConfig);
        Class<? extends T> dynamicType = new ByteBuddy()
                .subclass(interfaceType)
                .method(ElementMatchers.isDeclaredBy(interfaceType))
                .intercept(MethodDelegation.to(handler, "handler"))
                .make()
                .load(interfaceType.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
                .getLoaded();
        return  dynamicType.newInstance();
    }

    public static class ByteBuddyProxyHandler {
        private RpcxProxyConfig proxyConfig;
        public static final MediaType JSONTYPE = MediaType.get("application/json; charset=utf-8");
        public ByteBuddyProxyHandler(RpcxProxyConfig proxyConfig){
            this.proxyConfig = proxyConfig;

        }

        @RuntimeType
        public Object invoke(@Origin Method method, @AllArguments @RuntimeType Object[] args) throws Throwable {
            String name = method.getName();
            String serviceId = proxyConfig.getServiceId();
            String address = findAddress(serviceId);
            RpcfxRequest rpcfxRequest = new RpcfxRequest();
            rpcfxRequest.setParams(args);
            rpcfxRequest.setMethod(name);
            rpcfxRequest.setServiceClass(proxyConfig.getClassName());
            RpcfxResponse post = post(rpcfxRequest, address + "/" );
            return post.getResult();
        }


        private RpcfxResponse post(RpcfxRequest req, String url) throws IOException {
            String reqJson = JSON.toJSONString(req);
            System.out.println("req json: "+reqJson);

            // 1.可以复用client
            // 2.尝试使用httpclient或者netty client
            OkHttpClient client = new OkHttpClient();
            final Request request = new Request.Builder()
                    .url(url)
                    .post(RequestBody.create(JSONTYPE, reqJson))
                    .build();
            String respJson = client.newCall(request).execute().body().string();
            System.out.println("resp json: "+respJson);
            return JSON.parseObject(respJson, RpcfxResponse.class);
        }

        private String findAddress(String serviceId){
            return "http://"+serviceId;
        }
    }





}
